/*
 * This file is part of the Serial Flash Universal Driver Library.
 *
 * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Function: serial flash operate functions by SFUD lib.
 * Created on: 2016-04-23
 */

#include "sfud.h"
#include <string.h>

/* 读取数据时发送的虚拟数据（SPI 是全双工通信，读数据时需发送 dummy 字节产生时钟） */
#define DUMMY_DATA                               0xFF

// 断言：若未配置 Flash 设备表（sfud_cfg.h 中定义），编译报错（必须配置）
#ifndef SFUD_FLASH_DEVICE_TABLE
#error "Please configure the flash device information table in (in sfud_cfg.h)."
#endif

/* 用户配置的 Flash 设备信息表（从 sfud_cfg.h 导入，存储待初始化的 Flash 设备列表） */
static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
/* 支持的厂商信息表（存储主流 Flash 厂商 ID 和名称，用于识别厂商） */
static const sfud_mf mf_table[] = SFUD_MF_TABLE;

#ifdef SFUD_USING_FLASH_INFO_TABLE
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
#endif

#ifdef SFUD_USING_QSPI
/**
 * QSPI 模式下的 Flash 读取模式枚举（仅启用 QSPI 时生效）
 */
enum sfud_qspi_read_mode {
    NORMAL_SPI_READ = 1 << 0,               /**< 普通 SPI 读取模式 */
    DUAL_OUTPUT = 1 << 1,                   /**< QSPI 双输出快速读取 */
    DUAL_IO = 1 << 2,                       /**< QSPI 双输入/输出快速读取 */
    QUAD_OUTPUT = 1 << 3,                   /**< QSPI 四输出快速读取 */
    QUAD_IO = 1 << 4,                       /**< QSPI 四输入/输出快速读取 */
};

/* QSPI 模式下 Flash 扩展信息表（存储 QSPI 读取模式配置，与普通 SPI 分离） */
static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
#endif /* SFUD_USING_QSPI */

// 静态辅助函数声明（内部使用，不对外暴露）
static sfud_err software_init(const sfud_flash *flash);          // 软件初始化（目前为空，预留扩展）
static sfud_err hardware_init(sfud_flash *flash);                // 硬件初始化（核心：SPI 配置+芯片识别）
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
        const uint8_t *data);                                    // 256字节页写/1字节写（主流 Flash 写模式）
static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data); // 自动地址递增写（部分旧芯片支持）
static sfud_err wait_busy(const sfud_flash *flash);              // 等待 Flash 忙状态结束（擦除/写入后必需）
static sfud_err reset(const sfud_flash *flash);                  // 重置 Flash 芯片（恢复初始状态）
static sfud_err read_jedec_id(sfud_flash *flash);                // 读取 JEDEC ID（厂商ID+类型ID+容量ID，识别核心）
static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled); // 启用/禁用写操作（擦除/写入前必须启用）
static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled); // 切换 3/4 字节地址模式（容量>16MB 必需）
static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array); // 地址转换为字节数组（适配 SPI 命令格式）

/* 外部函数声明（来自 sfud_port.c，用户需实现：日志打印+SPI 底层初始化） */
extern void sfud_log_debug(const char *file, const long line, const char *format, ...); // 调试日志打印
extern void sfud_log_info(const char *format, ...);                                      // 信息日志打印

/**
 * @brief  单个 Flash 设备初始化（核心初始化函数）
 * @param  flash: 待初始化的 Flash 设备结构体（包含 SPI 配置、芯片参数等）
 * @return sfud_err: 初始化结果（SFUD_SUCCESS=成功）
 * @note   先执行硬件初始化（SPI 配置+芯片识别），再执行软件初始化（预留扩展）
 */
sfud_err sfud_device_init(sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;

    /* 步骤1：硬件初始化（SPI 引脚/时钟配置、Flash 芯片识别，最关键步骤） */
    result = hardware_init(flash);
    if (result == SFUD_SUCCESS) {
        /* 步骤2：软件初始化（目前无实际逻辑，预留后续扩展） */
        result = software_init(flash);
    }
    /* 步骤3：标记初始化状态 */
    if (result == SFUD_SUCCESS) {
        flash->init_ok = true;  // 初始化成功，标记为就绪
        SFUD_INFO("%s flash device initialized successfully.", flash->name);
    } else {
        flash->init_ok = false; // 初始化失败
        SFUD_INFO("Error: %s flash device initialization failed.", flash->name);
    }

    return result;
}

/**
 * @brief  SFUD 库全局初始化（初始化所有配置的 Flash 设备）
 * @return sfud_err: 全局初始化结果（所有设备均成功返回 SFUD_SUCCESS，否则返回第一个失败的错误码）
 * @note   遍历 flash_table 中的所有设备，逐个调用 sfud_device_init 初始化
 */
sfud_err sfud_init(void) {
    sfud_err cur_flash_result = SFUD_SUCCESS, all_flash_result = SFUD_SUCCESS;
    size_t i;

    SFUD_DEBUG("Start initialize Serial Flash Universal Driver(SFUD) V%s.", SFUD_SW_VERSION);
    SFUD_DEBUG("You can get the latest version on https://github.com/armink/SFUD .");
    /* 遍历所有 Flash 设备，逐个初始化 */
    for (i = 0; i < sizeof(flash_table) / sizeof(sfud_flash); i++) {
        /* 给当前设备分配索引（用于后续通过索引获取设备） */
        flash_table[i].index = i;
        cur_flash_result = sfud_device_init(&flash_table[i]);

        /* 记录全局结果：只要有一个设备初始化失败，全局结果为失败 */
        if (cur_flash_result != SFUD_SUCCESS) {
            all_flash_result = cur_flash_result;
        }
    }

    return all_flash_result;
}

/**
 * @brief  通过索引获取 Flash 设备（从 flash_table 中）
 * @param  index: 设备在 flash_table 中的索引
 * @return sfud_flash*: 成功返回设备指针，失败返回 NULL（索引超出范围）
 */
sfud_flash *sfud_get_device(size_t index) {
    if (index < sfud_get_device_num()) {
        return &flash_table[index];
    } else {
        return NULL;
    }
}

/**
 * @brief  获取 Flash 设备总数（flash_table 中的设备个数）
 * @return size_t: 设备总数
 */
size_t sfud_get_device_num(void) {
    return sizeof(flash_table) / sizeof(sfud_flash);
}

/**
 * @brief  获取 Flash 设备表指针（flash_table）
 * @return const sfud_flash*: 设备表指针
 */
const sfud_flash *sfud_get_device_table(void) {
    return flash_table;
}

#ifdef SFUD_USING_QSPI
/**
 * @brief  配置 QSPI 读取命令格式（仅 QSPI 模式生效）
 * @param  flash: Flash 设备指针
 * @param  ins: 读取命令（如 0x03=普通读）
 * @param  ins_lines: 命令传输线数（1/2/4）
 * @param  addr_lines: 地址传输线数（1/2/4）
 * @param  dummy_cycles: 虚拟时钟周期数（快速读取必需）
 * @param  data_lines: 数据传输线数（1/2/4）
 * @note   容量>16MB 时自动切换为 4 字节地址模式，命令需对应调整
 */
static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
        uint8_t dummy_cycles, uint8_t data_lines) {
    /* 容量≤16MB（2^24 字节）用 24 位地址，否则用 32 位地址 */
    if (flash->chip.capacity <= 0x1000000) {
        flash->read_cmd_format.instruction = ins;
        flash->read_cmd_format.address_size = 24;
    } else {
        if(ins == SFUD_CMD_READ_DATA){
            flash->read_cmd_format.instruction = ins + 0x10;
        }
        else{
            flash->read_cmd_format.instruction = ins + 1;
        }
        flash->read_cmd_format.address_size = 32;
    }

    flash->read_cmd_format.instruction_lines = ins_lines;
    flash->read_cmd_format.address_lines = addr_lines;
    flash->read_cmd_format.alternate_bytes_lines = 0;
    flash->read_cmd_format.dummy_cycles = dummy_cycles;
    flash->read_cmd_format.data_lines = data_lines;
}

/**
 * @brief  启用 QSPI 快速读取模式（仅 QSPI 模式生效）
 * @param  flash: Flash 设备指针
 * @param  data_line_width: QSPI 总线支持的最大数据线宽（1/2/4）
 * @return sfud_err: 操作结果（SFUD_SUCCESS=成功）
 * @note   需在 sfud_device_init 后调用，自动匹配 Flash 支持的最快读取模式
 */
sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
    size_t i = 0;
    uint8_t read_mode = NORMAL_SPI_READ;
    sfud_err result = SFUD_SUCCESS;

    SFUD_ASSERT(flash);
    SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);

    /* 从 QSPI 扩展表中匹配当前 Flash 支持的读取模式 */
    for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
        if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
                && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
                && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
            read_mode = qspi_flash_ext_info_table[i].read_mode;
        }
    }

    /* 根据总线线宽选择最优读取模式 */
    switch (data_line_width) {
    case 1:
        qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
        break;
    case 2:
        if (read_mode & DUAL_IO) {
            qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 4, 2);
        } else if (read_mode & DUAL_OUTPUT) {
            qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
        } else {
            qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
        }
        break;
    case 4:
        if (read_mode & QUAD_IO) {
            qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
        } else if (read_mode & QUAD_OUTPUT) {
            qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
        } else {
            qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
        }
        break;
    }

    return result;
}
#endif /* SFUD_USING_QSPI */

/**
 * @brief  硬件初始化（核心中的核心：SPI 配置+Flash 芯片识别）
 * @param  flash: Flash 设备指针（包含 SPI 配置、芯片参数存储区）
 * @return sfud_err: 初始化结果（SFUD_SUCCESS=成功）
 * @note   1. 先初始化 SPI 底层（引脚、时钟、读写函数绑定）
 *         2. 读取 JEDEC ID 识别芯片
 *         3. 优先通过 SFDP 读取芯片参数，失败则匹配内置芯片表（你已添加 GD25Q128E）
 *         4. 重置芯片+配置写保护+切换地址模式
 */
static sfud_err hardware_init(sfud_flash *flash) {
    // 外部函数声明：用户实现的 SPI 底层初始化（sfud_port.c 中，必须实现！）
    extern sfud_err sfud_spi_port_init(sfud_flash * flash);

    sfud_err result = SFUD_SUCCESS;  // 初始化结果
    size_t i;  // 循环变量

    SFUD_ASSERT(flash);  // 断言：设备指针非空

    /* 步骤1：初始化 SPI 底层（用户需实现 sfud_spi_port_init）
     * 作用：配置 SPI 引脚（SCK/MOSI/MISO/CS）、时钟、模式（Mode 0），并绑定 spi.wr 读写函数
     * 失败原因：SPI 引脚配置错误、时钟频率过高、读写函数未绑定
     */
    result = sfud_spi_port_init(flash);
    if (result != SFUD_SUCCESS) {
        return result;  // SPI 初始化失败，直接返回
    }

#ifdef SFUD_USING_QSPI
    /* QSPI 模式：默认初始化普通 SPI 读取命令（0x03） */
    flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
#endif /* SFUD_USING_QSPI */

    SFUD_ASSERT(flash->spi.wr);  // 断言：SPI 读写函数已绑定（sfud_spi_port_init 中必须赋值）

    /* 步骤2：识别 Flash 芯片参数（容量、写模式、擦除粒度等）
     * 若用户未手动配置这些参数，则通过 JEDEC ID + SFDP/内置表自动识别
     */
    if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
            || flash->chip.erase_gran_cmd == 0) {
        /* 步骤2.1：读取 JEDEC ID（厂商ID+类型ID+容量ID，识别的基础）
         * 失败原因：SPI 通信未通（MISO 接线错误、CS 未拉低、模式不匹配），表现为 ID 全 0xFF
         */
        result = read_jedec_id(flash);
        if (result != SFUD_SUCCESS) {
            return result;  // JEDEC ID 读取失败，直接返回
        }

#ifdef SFUD_USING_SFDP
        // 外部函数声明：读取 SFDP 表（Flash 自描述参数表，包含所有芯片参数）
        extern bool sfud_read_sfdp(sfud_flash *flash);
        /* 步骤2.2：优先通过 SFDP 识别芯片（主流芯片如 GD25Q128E 均支持，最可靠）
         * 流程：发送 0x5A 命令读取 SFDP 表 → 验证签名（0x50444653 = "SFDP"）→ 提取参数
         */
        if (sfud_read_sfdp(flash)) {
            flash->chip.name = NULL;  // SFDP 识别成功，无需使用内置表名称
            flash->chip.capacity = flash->sfdp.capacity;  // 从 SFDP 提取容量

            // 从 SFDP 提取写模式（1字节写/256字节页写）
            if (flash->sfdp.write_gran == 1) {
                flash->chip.write_mode = SFUD_WM_BYTE;  // 1字节写模式
            } else {
                flash->chip.write_mode = SFUD_WM_PAGE_256B;  // 256字节页写模式（GD25Q128E 支持）
            }

            // 从 SFDP 提取擦除粒度（选择最小粒度，保证兼容性）
            flash->chip.erase_gran = flash->sfdp.eraser[0].size;
            flash->chip.erase_gran_cmd = flash->sfdp.eraser[0].cmd;
            for (i = 1; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
                if (flash->sfdp.eraser[i].size != 0 && flash->chip.erase_gran > flash->sfdp.eraser[i].size) {
                    flash->chip.erase_gran = flash->sfdp.eraser[i].size;  // 最小擦除粒度（如 4KB）
                    flash->chip.erase_gran_cmd = flash->sfdp.eraser[i].cmd;  // 对应命令（如 0x20）
                }
            }
        } else {
#endif  /* SFUD_USING_SFDP 开始 */

#ifdef SFUD_USING_FLASH_INFO_TABLE
            /* 步骤2.3：SFDP 识别失败，匹配内置芯片表（你已添加 GD25Q128E）
             * 匹配逻辑：用 JEDEC ID（厂商ID+类型ID+容量ID）比对 flash_chip_table
             * 成功：提取表中参数（容量16MB、擦除粒度4KB、命令0x20等）
             * 失败：返回 SFUD_ERR_NOT_FOUND（芯片未支持）
             */
            for (i = 0; i < sizeof(flash_chip_table) / sizeof(sfud_flash_chip); i++) {
                if ((flash_chip_table[i].mf_id == flash->chip.mf_id)
                        && (flash_chip_table[i].type_id == flash->chip.type_id)
                        && (flash_chip_table[i].capacity_id == flash->chip.capacity_id)) {
                    // 匹配成功，复制芯片参数到 flash->chip
                    flash->chip.name = flash_chip_table[i].name;
                    flash->chip.capacity = flash_chip_table[i].capacity;
                    flash->chip.write_mode = flash_chip_table[i].write_mode;
                    flash->chip.erase_gran = flash_chip_table[i].erase_gran;
                    flash->chip.erase_gran_cmd = flash_chip_table[i].erase_gran_cmd;
                    break;
                }
            }
#endif  /* SFUD_USING_FLASH_INFO_TABLE 结束 */

#ifdef SFUD_USING_SFDP
        }
#endif  /* SFUD_USING_SFDP 结束 */

    }

    /* 步骤3：校验芯片参数（若容量、写模式、擦除粒度仍为0，说明识别失败） */
    if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
            || flash->chip.erase_gran_cmd == 0) {
        SFUD_INFO("Warning: This flash device is not found or not supported.");
        return SFUD_ERR_NOT_FOUND;  // 芯片未识别，返回失败
    } else {
        /* 步骤3.1：打印识别结果（厂商+型号+容量，方便调试） */
        const char *flash_mf_name = NULL;
        // 匹配厂商名称（从 mf_table 中通过厂商ID查找）
        for (i = 0; i < sizeof(mf_table) / sizeof(sfud_mf); i++) {
            if (mf_table[i].id == flash->chip.mf_id) {
                flash_mf_name = mf_table[i].name;
                break;
            }
        }
        // 打印识别信息
        if (flash_mf_name && flash->chip.name) {
            SFUD_INFO("Found a %s %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.name,
                    flash->chip.capacity);
        } else if (flash_mf_name) {
            SFUD_INFO("Found a %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.capacity);
        } else {
            SFUD_INFO("Found a flash chip. Size is %ld bytes.", flash->chip.capacity);
        }
    }

    /* 步骤4：重置 Flash 芯片（恢复初始状态，清除异常状态） */
    result = reset(flash);
    if (result != SFUD_SUCCESS) {
        return result;  // 重置失败，返回
    }

    /* 步骤5：配置写保护（禁用写保护，允许擦除/写入） */
    if (flash->chip.write_mode & SFUD_WM_AAI) {
        // AAI 写模式芯片：通过写状态寄存器禁用保护
        result = sfud_write_status(flash, true, 0x00);
    } else {
        // 特殊芯片（如 MX25L3206E）：单独处理写保护
        if ((0xC2 == flash->chip.mf_id) && (0x20 == flash->chip.type_id) && (0x16 == flash->chip.capacity_id)) {
            result = sfud_write_status(flash, false, 0x00);
        }
    }
    if (result != SFUD_SUCCESS) {
        return result;  // 写保护配置失败，返回
    }

    /* 步骤6：切换地址模式（容量>16MB 需 4 字节地址，否则 3 字节）
     * GD25Q128E 容量 16MB（=2^24 字节），刚好使用 3 字节地址，无需切换
     */
    if (flash->chip.capacity > (1L << 24)) {
        result = set_4_byte_address_mode(flash, true);  // 切换为 4 字节地址
    } else {
        flash->addr_in_4_byte = false;  // 3 字节地址模式
    }

    return result;  // 硬件初始化成功
}

/**
 * @brief  软件初始化（预留扩展函数，目前无实际逻辑）
 * @param  flash: Flash 设备指针
 * @return sfud_err: 固定返回 SFUD_SUCCESS
 */
static sfud_err software_init(const sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;

    SFUD_ASSERT(flash);

    return result;
}

/**
 * @brief  读取 Flash 数据（支持普通读/快速读/QSPI 读）
 * @param  flash: Flash 设备指针（需已初始化）
 * @param  addr: 读取起始地址（必须在有效容量范围内）
 * @param  size: 读取数据大小（字节）
 * @param  data: 接收数据的缓冲区指针（必须非空且有效）
 * @return sfud_err: 读取结果（SFUD_SUCCESS=成功）
 * @note   1. 读取前需等待 Flash 空闲（非忙状态）
 *         2. QSPI 模式自动使用快速读，普通 SPI 支持普通读/快速读（需启用 SFUD_USING_FAST_READ）
 */
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[5 + SFUD_READ_DUMMY_BYTE_CNT];  // 命令缓冲区（命令+地址+dummy）
    uint8_t cmd_size;  // 命令总长度

    SFUD_ASSERT(flash);
    SFUD_ASSERT(data);
    SFUD_ASSERT(flash->init_ok);  // 断言：设备已初始化
    /* 检查地址范围（addr + size 不能超出 Flash 容量） */
    if (addr + size > flash->chip.capacity) {
        SFUD_INFO("Error: Flash address is out of bound.");
        return SFUD_ERR_ADDR_OUT_OF_BOUND;
    }
    /* 锁定 SPI 总线（多任务安全） */
    if (spi->lock) {
        spi->lock(spi);
    }

    /* 等待 Flash 空闲（避免在擦除/写入时读取） */
    result = wait_busy(flash);

    if (result == SFUD_SUCCESS) {
#ifdef SFUD_USING_QSPI
        // QSPI 模式：使用配置的快速读命令
        if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
            result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
        } else
#endif
        {
            // 普通 SPI 模式：选择读命令（普通读/快速读）
#ifdef SFUD_USING_FAST_READ
            cmd_data[0] = SFUD_CMD_FAST_READ_DATA;  // 快速读命令（0x0B）
#else
            cmd_data[0] = SFUD_CMD_READ_DATA;       // 普通读命令（0x03）
#endif
            // 地址转换为字节数组（填充到命令缓冲区）
            make_address_byte_array(flash, addr, &cmd_data[1]);
            // 计算命令长度（3字节地址=4字节，4字节地址=5字节）
            cmd_size = flash->addr_in_4_byte ? 5 : 4;
#ifdef SFUD_USING_FAST_READ
            // 快速读需添加 dummy 字节（产生足够时钟）
            for (uint8_t i = 0; i < SFUD_READ_DUMMY_BYTE_CNT; i++) {
                cmd_data[cmd_size] = SFUD_DUMMY_DATA;
                cmd_size++;
            }
#endif
            // 发送命令+地址+dummy，接收数据
            result = spi->wr(spi, cmd_data, cmd_size, data, size);
        }
    }
    /* 解锁 SPI 总线 */
    if (spi->unlock) {
        spi->unlock(spi);
    }

    return result;
}

/**
 * @brief  整芯片擦除（擦除所有数据，速度较慢但操作简单）
 * @param  flash: Flash 设备指针（需已初始化）
 * @return sfud_err: 擦除结果（SFUD_SUCCESS=成功）
 * @note   1. 擦除前必须启用写使能
 *         2. 特殊芯片（如 AT45DB 系列）擦除命令不同，已适配
 *         3. 擦除后需等待忙状态结束（整芯片擦除可能需数秒）
 */
sfud_err sfud_chip_erase(const sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[4];  // 命令缓冲区

    SFUD_ASSERT(flash);
    SFUD_ASSERT(flash->init_ok);  // 断言：设备已初始化
    /* 锁定 SPI 总线 */
    if (spi->lock) {
        spi->lock(spi);
    }

    /* 步骤1：启用写使能（擦除前必需，否则硬件忽略命令） */
    result = set_write_enabled(flash, true);
    if (result != SFUD_SUCCESS) {
        goto __exit;
    }

    cmd_data[0] = SFUD_CMD_ERASE_CHIP;  // 整芯片擦除命令（0xC7）
    /* 双缓冲芯片（如 AT45DB 系列）：擦除命令格式不同，单独处理 */
    if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
        cmd_data[1] = 0x94;
        cmd_data[2] = 0x80;
        cmd_data[3] = 0x9A;
        result = spi->wr(spi, cmd_data, 4, NULL, 0);
    } else {
        // 普通芯片：发送单字节擦除命令
        result = spi->wr(spi, cmd_data, 1, NULL, 0);
    }
    if (result != SFUD_SUCCESS) {
        SFUD_INFO("Error: Flash chip erase SPI communicate error.");
        goto __exit;
    }
    /* 步骤2：等待擦除完成（整芯片擦除耗时较长，需足够超时时间） */
    result = wait_busy(flash);

__exit:
    /* 步骤3：禁用写使能（擦除后安全收尾） */
    set_write_enabled(flash, false);
    /* 解锁 SPI 总线 */
    if (spi->unlock) {
        spi->unlock(spi);
    }

    return result;
}

/**
 * @brief  扇区/块擦除（指定地址范围擦除，支持部分擦除）
 * @param  flash: 已初始化的Flash设备结构体指针（包含SPI配置、容量、擦除命令等信息）
 * @param  addr: 擦除起始地址（必须在Flash有效地址范围内，单位：字节）
 * @param  size: 待擦除的大小（单位：字节，需为擦除粒度的整数倍或兼容范围）
 * @return sfud_err: 操作结果（SFUD_SUCCESS=成功，其他值=对应错误码）
 * @note   1. Flash擦除只能按固定粒度（如4KB扇区、64KB块）执行，函数会自动拆分范围并按粒度擦除
 *         2. 擦除后数据会被置为0xFF（Flash的默认空值），且擦除是耗时操作（需等待Flash忙状态结束）
 */
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) {
    // 外部函数声明：从SFDP（Flash自描述参数表）中获取当前地址适配的擦除方式（命令+粒度）
    extern size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size);

    sfud_err result = SFUD_SUCCESS;          // 函数返回结果（默认初始化成功）
    const sfud_spi *spi = &flash->spi;       // 获取SPI配置结构体（包含SPI读写函数、锁操作等）
    uint8_t cmd_data[5];                     // 擦除命令缓冲区（1字节命令 + 3/4字节地址）
    uint8_t cmd_size;                        // 命令总长度（随地址位数变化：24位地址=4字节，32位=5字节）
    uint8_t cur_erase_cmd;                   // 当前擦除操作使用的SPI命令（如0x20=4KB扇区擦除）
    size_t cur_erase_size;                   // 当前擦除操作的粒度（如4096字节=4KB，由Flash特性决定）

    // 断言：确保Flash设备指针有效（避免空指针访问）
    SFUD_ASSERT(flash);
    // 断言：必须在Flash初始化成功后才能调用擦除函数（未初始化的设备无法执行操作）
    SFUD_ASSERT(flash->init_ok);
    // 检查擦除地址范围是否超出Flash总容量（addr + size 不能超过芯片最大地址）
    if (addr + size > flash->chip.capacity) {
        SFUD_INFO("Error: Flash address is out of bound.");  // 打印地址越界日志
        return SFUD_ERR_ADDR_OUT_OF_BOUND;                   // 返回地址越界错误码
    }

    // 若擦除范围是整个芯片（从0地址开始，且大小等于芯片总容量），直接调用整芯片擦除函数
    // 整芯片擦除比逐块擦除更高效（硬件层面优化）
    if (addr == 0 && size == flash->chip.capacity) {
        return sfud_chip_erase(flash);
    }

    // 锁定SPI总线（若配置了锁函数）：避免多任务同时操作SPI导致命令冲突（如A任务擦除时B任务写入）
    if (spi->lock) {
        spi->lock(spi);
    }

    // 循环执行擦除操作：按擦除粒度拆分总大小，逐块擦除直到完成
    while (size) {
        // 根据是否启用SFDP，选择当前地址适配的擦除命令和粒度
#ifdef SFUD_USING_SFDP  // 若启用SFDP（编译时配置）
        size_t eraser_index;  // 擦除方式索引（SFDP表中的条目索引）
        if (flash->sfdp.available) {  // 若当前Flash支持SFDP（已读取并验证SFDP表）
            // 从SFDP表中获取最适合当前地址和剩余大小的擦除方式（自动匹配最优粒度）
            eraser_index = sfud_sfdp_get_suitable_eraser(flash, addr, size);
            cur_erase_cmd = flash->sfdp.eraser[eraser_index].cmd;  // 从SFDP中获取擦除命令
            cur_erase_size = flash->sfdp.eraser[eraser_index].size;  // 从SFDP中获取擦除粒度
        } else {
#else  // 未启用SFDP，使用芯片信息表中的默认擦除参数（手动配置的粒度和命令）
        {
#endif
            cur_erase_cmd = flash->chip.erase_gran_cmd;  // 从芯片信息中获取擦除命令（如0x20）
            cur_erase_size = flash->chip.erase_gran;      // 从芯片信息中获取擦除粒度（如4096字节）
        }

        // 步骤1：发送写使能命令（Flash擦除/写入前必须执行，否则操作会被硬件忽略）
        result = set_write_enabled(flash, true);
        if (result != SFUD_SUCCESS) {  // 写使能失败（如SPI通信错误），跳转到退出流程
            goto __exit;
        }

        // 步骤2：构造擦除命令帧
        cmd_data[0] = cur_erase_cmd;                  // 第1字节：擦除命令（如0x20=4KB扇区擦除）
        // 将擦除起始地址转换为字节数组，填充到命令缓冲区（地址长度由Flash位数决定：24位/32位）
        make_address_byte_array(flash, addr, &cmd_data[1]);
        // 计算命令总长度：32位地址需要5字节（1命令+4地址），24位地址需要4字节（1命令+3地址）
        cmd_size = flash->addr_in_4_byte ? 5 : 4;

        // 步骤3：通过SPI发送擦除命令（擦除命令无需读取返回数据，故读缓冲区为NULL，长度0）
        result = spi->wr(spi, cmd_data, cmd_size, NULL, 0);
        if (result != SFUD_SUCCESS) {  // SPI发送失败（如超时、数据错误）
            SFUD_INFO("Error: Flash erase SPI communicate error.");
            goto __exit;
        }

        // 步骤4：等待擦除完成（擦除是耗时操作，需等待Flash忙标志位清除）
        // 若不等待，直接执行后续操作可能导致命令冲突（Flash正在擦除时不响应新命令）
        result = wait_busy(flash);
        if (result != SFUD_SUCCESS) {  // 等待超时（擦除时间过长）或忙标志异常
            goto __exit;
        }

        // 步骤5：更新剩余擦除大小和地址（按擦除粒度对齐，确保下一次擦除地址合法）
        if (addr % cur_erase_size != 0) {  // 起始地址未按当前擦除粒度对齐（需先擦除到对齐位置）
            // 计算从当前地址到下一个对齐地址的长度（需擦除的"头部"）
            size_t align_size = cur_erase_size - (addr % cur_erase_size);
            if (size > align_size) {  // 剩余大小足够覆盖"头部"，继续擦除剩余部分
                size -= align_size;   // 减去已擦除的"头部"大小
                addr += align_size;   // 地址移到下一个对齐位置
            } else {  // 剩余大小不足覆盖"头部"，本次擦除已完成（剩余部分包含在当前粒度内）
                goto __exit;
            }
        } else {  // 起始地址已对齐，直接按当前粒度擦除
            if (size > cur_erase_size) {  // 剩余大小超过一个擦除粒度，继续擦除下一个粒度
                size -= cur_erase_size;   // 减去当前擦除的粒度大小
                addr += cur_erase_size;   // 地址移到下一个粒度位置
            } else {  // 剩余大小不足一个擦除粒度，本次擦除已完成（剩余部分包含在当前粒度内）
                goto __exit;
            }
        }
    }

__exit:  // 退出标签：统一处理资源释放和收尾操作（无论成功/失败均执行）
    // 发送写禁用命令（擦除完成后禁用写操作，防止误操作修改Flash数据）
    set_write_enabled(flash, false);
    // 解锁SPI总线（若之前锁定过）：释放SPI资源，允许其他任务操作
    if (spi->unlock) {
        spi->unlock(spi);
    }

    return result;  // 返回最终操作结果（成功/错误码）
}

/**
 * @brief  256字节页写/1字节写（无擦除，需先擦除再写入）
 * @param  flash: Flash 设备指针（需已初始化）
 * @param  addr: 写入起始地址
 * @param  size: 写入大小（字节）
 * @param  write_gran: 写入粒度（1或256，对应1字节写/256字节页写）
 * @param  data: 待写入数据缓冲区
 * @return sfud_err: 写入结果（SFUD_SUCCESS=成功）
 * @note   1. Flash 写操作不能覆盖非0xFF数据，必须先擦除对应扇区
 *         2. 页写时数据不能跨页（256字节/页），函数会自动拆分跨页数据
 */
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
        const uint8_t *data) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];  // 命令+地址+数据缓冲区
    uint8_t cmd_size;  // 命令长度
    size_t data_size;  // 本次写入数据大小（不超过写入粒度）

    SFUD_ASSERT(flash);
    SFUD_ASSERT(write_gran == 1 || write_gran == 256);  // 仅支持1字节/256字节粒度
    SFUD_ASSERT(flash->init_ok);
    /* 检查地址范围 */
    if (addr + size > flash->chip.capacity) {
        SFUD_INFO("Error: Flash address is out of bound.");
        return SFUD_ERR_ADDR_OUT_OF_BOUND;
    }
    /* 锁定 SPI 总线 */
    if (spi->lock) {
        spi->lock(spi);
    }

    /* 循环写入：按写入粒度拆分数据，避免跨页/超粒度 */
    while (size) {
        /* 步骤1：启用写使能（写入前必需） */
        result = set_write_enabled(flash, true);
        if (result != SFUD_SUCCESS) {
            goto __exit;
        }
        cmd_data[0] = SFUD_CMD_PAGE_PROGRAM;  // 页编程命令（0x02，支持1字节/256字节写）
        make_address_byte_array(flash, addr, &cmd_data[1]);  // 填充地址
        cmd_size = flash->addr_in_4_byte ? 5 : 4;  // 命令长度

        /* 计算本次写入数据大小（按粒度对齐，不跨页） */
        if (addr % write_gran != 0) {
            // 地址未对齐，先写到对齐位置
            if (size > write_gran - (addr % write_gran)) {
                data_size = write_gran - (addr % write_gran);
            } else {
                data_size = size;
            }
        } else {
            // 地址已对齐，按粒度写入（不超过剩余大小）
            if (size > write_gran) {
                data_size = write_gran;
            } else {
                data_size = size;
            }
        }
        // 更新剩余大小、地址、数据指针
        size -= data_size;
        addr += data_size;

        // 将待写入数据复制到命令缓冲区（命令+地址之后）
        memcpy(&cmd_data[cmd_size], data, data_size);

        // 发送命令+地址+数据（无返回数据）
        result = spi->wr(spi, cmd_data, cmd_size + data_size, NULL, 0);
        if (result != SFUD_SUCCESS) {
            SFUD_INFO("Error: Flash write SPI communicate error.");
            goto __exit;
        }
        /* 步骤2：等待写入完成（页写耗时较短，约数微秒） */
        result = wait_busy(flash);
        if (result != SFUD_SUCCESS) {
            goto __exit;
        }
        data += data_size;  // 数据指针偏移
    }

__exit:
    /* 禁用写使能 */
    set_write_enabled(flash, false);
    /* 解锁 SPI 总线 */
    if (spi->unlock) {
        spi->unlock(spi);
    }

    return result;
}

/**
 * @brief  自动地址递增写（AAI 模式，部分旧芯片支持）
 * @param  flash: Flash 设备指针
 * @param  addr: 写入起始地址
 * @param  size: 写入大小（字节）
 * @param  data: 待写入数据缓冲区
 * @return sfud_err: 写入结果（SFUD_SUCCESS=成功）
 * @note   1. 地址必须为偶数，奇数地址会自动填充0xFF
 *         2. 写入大小为奇数时，末尾自动填充0xFF
 *         3. 无需每次写都发送地址，仅首次发送（自动递增）
 */
static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[8], cmd_size;
    bool first_write = true;  // 标记是否为首次写入（需发送地址）

    SFUD_ASSERT(flash);
    SFUD_ASSERT(flash->init_ok);
    /* 检查地址范围 */
    if (addr + size > flash->chip.capacity) {
        SFUD_INFO("Error: Flash address is out of bound.");
        return SFUD_ERR_ADDR_OUT_OF_BOUND;
    }
    /* 锁定 SPI 总线 */
    if (spi->lock) {
        spi->lock(spi);
    }
    /* AAI 模式要求地址为偶数，奇数地址先单独写1字节 */
    if (addr % 2 != 0) {
        result = page256_or_1_byte_write(flash, addr++, 1, 1, data++);
        if (result != SFUD_SUCCESS) {
            goto __exit;
        }
        size--;
    }
    /* 启用写使能 */
    result = set_write_enabled(flash, true);
    if (result != SFUD_SUCCESS) {
        goto __exit;
    }
    cmd_data[0] = SFUD_CMD_AAI_WORD_PROGRAM;  // AAI 写命令（0xAD）
    /* 循环写入（每次写2字节） */
    while (size >= 2) {
        if (first_write) {
            // 首次写入：发送命令+地址+2字节数据
            make_address_byte_array(flash, addr, &cmd_data[1]);
            cmd_size = flash->addr_in_4_byte ? 5 : 4;
            cmd_data[cmd_size] = *data;
            cmd_data[cmd_size + 1] = *(data + 1);
            first_write = false;
        } else {
            // 非首次写入：仅发送命令+2字节数据（地址自动递增）
            cmd_size = 1;
            cmd_data[1] = *data;
            cmd_data[2] = *(data + 1);
        }

        // 发送数据
        result = spi->wr(spi, cmd_data, cmd_size + 2, NULL, 0);
        if (result != SFUD_SUCCESS) {
            SFUD_INFO("Error: Flash write SPI communicate error.");
            goto __exit;
        }

        // 等待写入完成
        result = wait_busy(flash);
        if (result != SFUD_SUCCESS) {
            goto __exit;
        }

        // 更新剩余大小、地址、数据指针
        size -= 2;
        addr += 2;
        data += 2;
    }
    /* 禁用写使能（退出 AAI 模式） */
    result = set_write_enabled(flash, false);
    /* 写入剩余1字节（若大小为奇数） */
    if (result == SFUD_SUCCESS && size == 1) {
        result = page256_or_1_byte_write(flash, addr, 1, 1, data);
    }

__exit:
    if (result != SFUD_SUCCESS) {
        set_write_enabled(flash, false);
    }
    /* 解锁 SPI 总线 */
    if (spi->unlock) {
        spi->unlock(spi);
    }

    return result;
}

/**
 * @brief  Flash 写入（无擦除，需先擦除对应扇区）
 * @param  flash: Flash 设备指针（需已初始化）
 * @param  addr: 写入起始地址
 * @param  size: 写入大小（字节）
 * @param  data: 待写入数据缓冲区
 * @return sfud_err: 写入结果（SFUD_SUCCESS=成功）
 * @note   1. 自动根据芯片写模式选择写入方式（256字节页写/AAI写/双缓冲写）
 *         2. GD25Q128E 支持 256字节页写（SFUD_WM_PAGE_256B），会调用 page256_or_1_byte_write
 */
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
    sfud_err result = SFUD_SUCCESS;

    if (flash->chip.write_mode & SFUD_WM_PAGE_256B) {
        // 256字节页写模式（主流芯片，如 GD25Q128E）
        result = page256_or_1_byte_write(flash, addr, size, 256, data);
    } else if (flash->chip.write_mode & SFUD_WM_AAI) {
        // AAI 自动地址递增写模式（部分旧芯片）
        result = aai_write(flash, addr, size, data);
    } else if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
        // 双缓冲写模式（如 AT45DB 系列，预留实现）
        //TODO dual-buffer write mode
    }

    return result;
}

/**
 * @brief  擦除后写入（先擦除指定范围，再写入数据，最常用的写入接口）
 * @param  flash: Flash 设备指针（需已初始化）
 * @param  addr: 操作起始地址
 * @param  size: 操作大小（字节）
 * @param  data: 待写入数据缓冲区
 * @return sfud_err: 操作结果（SFUD_SUCCESS=成功）
 * @note   1. 自动完成“擦除→写入”流程，无需手动调用 sfud_erase
 *         2. 擦除粒度为芯片最小擦除单位（如 GD25Q128E 为4KB），会自动对齐地址
 */
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
    sfud_err result = SFUD_SUCCESS;

    /* 步骤1：擦除指定范围 */
    result = sfud_erase(flash, addr, size);

    /* 步骤2：擦除成功后写入数据 */
    if (result == SFUD_SUCCESS) {
        result = sfud_write(flash, addr, size, data);
    }

    return result;
}

/**
 * @brief  重置 Flash 芯片（恢复初始状态）
 * @param  flash: Flash 设备指针
 * @return sfud_err: 重置结果（SFUD_SUCCESS=成功）
 * @note   流程：发送启用重置命令（0x66）→ 发送重置命令（0x99）→ 等待忙状态结束
 */
static sfud_err reset(const sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[2];

    SFUD_ASSERT(flash);

    cmd_data[0] = SFUD_CMD_ENABLE_RESET;  // 启用重置命令（0x66）
    result = spi->wr(spi, cmd_data, 1, NULL, 0);
    if (result == SFUD_SUCCESS) {
        result = wait_busy(flash);
    } else {
        SFUD_INFO("Error: Flash device reset failed.");
        return result;
    }

    cmd_data[1] = SFUD_CMD_RESET;  // 重置命令（0x99）
    result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);

    if (result == SFUD_SUCCESS) {
        result = wait_busy(flash);
    }

    if (result == SFUD_SUCCESS) {
        SFUD_DEBUG("Flash device reset success.");
    } else {
        SFUD_INFO("Error: Flash device reset failed.");
    }

    return result;
}

/**
 * @brief  读取 JEDEC ID（厂商ID+类型ID+容量ID）
 * @param  flash: Flash 设备指针（存储读取到的 ID）
 * @return sfud_err: 读取结果（SFUD_SUCCESS=成功）
 * @note   1. 命令：0x9F（JEDEC ID 读取命令，所有芯片通用）
 *         2. 读取到的 ID 存储在 flash->chip.mf_id/type_id/capacity_id
 *         3. 失败表现：ID 全为 0xFF，原因是 SPI 通信未通（你之前的核心问题）
 */
static sfud_err read_jedec_id(sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[1], recv_data[3];

    SFUD_ASSERT(flash);

    cmd_data[0] = SFUD_CMD_JEDEC_ID;  // 读取 JEDEC ID 命令（0x9F）
    // 发送命令，接收3字节 ID（厂商ID+类型ID+容量ID）
    result = spi->wr(spi, cmd_data, sizeof(cmd_data), recv_data, sizeof(recv_data));
    if (result == SFUD_SUCCESS) {
        // 存储读取到的 ID
        flash->chip.mf_id = recv_data[0];
        flash->chip.type_id = recv_data[1];
        flash->chip.capacity_id = recv_data[2];
        SFUD_DEBUG("The flash device manufacturer ID is 0x%02X, memory type ID is 0x%02X, capacity ID is 0x%02X.",
                flash->chip.mf_id, flash->chip.type_id, flash->chip.capacity_id);
    } else {
        SFUD_INFO("Error: Read flash device JEDEC ID error.");
    }

    return result;
}

/**
 * @brief  启用/禁用 Flash 写操作
 * @param  flash: Flash 设备指针
 * @param  enabled: true=启用写，false=禁用写
 * @return sfud_err: 操作结果（SFUD_SUCCESS=成功）
 * @note   1. 启用写（0x06 命令）：擦除/写入前必须执行
 *         2. 禁用写（0x04 命令）：操作完成后执行，防止误操作
 *         3. 启用后会读取状态寄存器验证（WEL 位=1 表示启用成功）
 */
static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled) {
    sfud_err result = SFUD_SUCCESS;
    uint8_t cmd, register_status;

    SFUD_ASSERT(flash);

    // 选择命令（启用/禁用写）
    if (enabled) {
        cmd = SFUD_CMD_WRITE_ENABLE;  // 启用写命令（0x06）
    } else {
        cmd = SFUD_CMD_WRITE_DISABLE; // 禁用写命令（0x04）
    }

    // 发送命令
    result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);

    // 验证操作结果（读取状态寄存器）
    if (result == SFUD_SUCCESS) {
        result = sfud_read_status(flash, &register_status);
    }

    // 检查状态寄存器的 WEL 位（写使能位）
    if (result == SFUD_SUCCESS) {
        if (enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 0) {
            SFUD_INFO("Error: Can't enable write status.");
            return SFUD_ERR_WRITE;
        } else if (!enabled && (register_status & SFUD_STATUS_REGISTER_WEL) != 0) {
            SFUD_INFO("Error: Can't disable write status.");
            return SFUD_ERR_WRITE;
        }
    }

    return result;
}

/**
 * @brief  切换 3/4 字节地址模式
 * @param  flash: Flash 设备指针
 * @param  enabled: true=启用4字节地址，false=禁用（3字节）
 * @return sfud_err: 切换结果（SFUD_SUCCESS=成功）
 * @note   1. 仅容量>16MB（2^24 字节）的芯片需要启用4字节地址
 *         2. GD25Q128E 容量16MB，无需启用，默认3字节地址
 */
static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled) {
    sfud_err result = SFUD_SUCCESS;
    uint8_t cmd;

    SFUD_ASSERT(flash);

    /* 启用写使能（修改地址模式需写权限） */
    result = set_write_enabled(flash, true);
    if (result != SFUD_SUCCESS) {
        return result;
    }

    // 选择命令（进入/退出4字节地址模式）
    if (enabled) {
        cmd = SFUD_CMD_ENTER_4B_ADDRESS_MODE;  // 进入4字节地址命令（0xB7）
    } else {
        cmd = SFUD_CMD_EXIT_4B_ADDRESS_MODE;   // 退出4字节地址命令（0xE9）
    }

    // 发送命令
    result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);

    // 标记地址模式
    if (result == SFUD_SUCCESS) {
        flash->addr_in_4_byte = enabled ? true : false;
        SFUD_DEBUG("%s 4-Byte addressing mode success.", enabled ? "Enter" : "Exit");
    } else {
        SFUD_INFO("Error: %s 4-Byte addressing mode failed.", enabled ? "Enter" : "Exit");
    }

    return result;
}

/**
 * @brief  读取 Flash 状态寄存器（主要用于检查忙状态和写使能状态）
 * @param  flash: Flash 设备指针
 * @param  status: 存储状态寄存器值的指针
 * @return sfud_err: 读取结果（SFUD_SUCCESS=成功）
 * @note   命令：0x05（读取状态寄存器1），状态寄存器第0位为忙位（1=忙，0=空闲）
 */
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) {
    uint8_t cmd = SFUD_CMD_READ_STATUS_REGISTER;  // 读取状态寄存器命令（0x05）

    SFUD_ASSERT(flash);
    SFUD_ASSERT(status);

    // 发送命令，接收1字节状态寄存器值
    return flash->spi.wr(&flash->spi, &cmd, 1, status, 1);
}

/**
 * @brief  等待 Flash 忙状态结束（擦除/写入后必需）
 * @param  flash: Flash 设备指针
 * @return sfud_err: 等待结果（SFUD_SUCCESS=空闲，SFUD_ERR_TIMEOUT=超时）
 * @note   循环读取状态寄存器，直到忙位为0或超时
 */
static sfud_err wait_busy(const sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;
    uint8_t status;
    size_t retry_times = flash->retry.times;  // 超时重试次数

    SFUD_ASSERT(flash);

    while (true) {
        // 读取状态寄存器
        result = sfud_read_status(flash, &status);
        // 忙位为0（空闲），退出等待
        if (result == SFUD_SUCCESS && ((status & SFUD_STATUS_REGISTER_BUSY)) == 0) {
            break;
        }
        // 超时重试处理（超过次数返回失败）
        SFUD_RETRY_PROCESS(flash->retry.delay, retry_times, result);
    }

    // 检查等待结果（超时或仍忙）
    if (result != SFUD_SUCCESS || ((status & SFUD_STATUS_REGISTER_BUSY)) != 0) {
        SFUD_INFO("Error: Flash wait busy has an error.");
    }

    return result;
}

/**
 * @brief  将地址转换为字节数组（适配 SPI 命令格式）
 * @param  flash: Flash 设备指针（包含地址模式：3/4字节）
 * @param  addr: 待转换的地址（32位）
 * @param  array: 存储字节数组的缓冲区（长度≥3或4）
 * @note   地址字节序为大端（高位在前），如地址 0x123456：
 *         3字节地址→array[0]=0x12, array[1]=0x34, array[2]=0x56
 *         4字节地址→array[0]=0x00, array[1]=0x12, array[2]=0x34, array[3]=0x56
 */
static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array) {
    uint8_t len, i;

    SFUD_ASSERT(flash);
    SFUD_ASSERT(array);

    // 地址长度（3或4字节）
    len = flash->addr_in_4_byte ? 4 : 3;

    // 地址转换为大端字节数组
    for (i = 0; i < len; i++) {
        array[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
    }
}

/**
 * @brief  写入状态寄存器（配置写保护、块保护等）
 * @param  flash: Flash 设备指针
 * @param  is_volatile: true=易失性模式（断电失效），false=非易失性模式（断电保存）
 * @param  status: 待写入的状态寄存器值
 * @return sfud_err: 写入结果（SFUD_SUCCESS=成功）
 */
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) {
    sfud_err result = SFUD_SUCCESS;
    const sfud_spi *spi = &flash->spi;
    uint8_t cmd_data[2];

    SFUD_ASSERT(flash);

    // 易失性模式：先发送 volatile 写使能命令
    if (is_volatile) {
        cmd_data[0] = SFUD_VOLATILE_SR_WRITE_ENABLE;
        result = spi->wr(spi, cmd_data, 1, NULL, 0);
    } else {
        // 非易失性模式：发送普通写使能命令
        result = set_write_enabled(flash, true);
    }

    // 发送写状态寄存器命令+数据
    if (result == SFUD_SUCCESS) {
        cmd_data[0] = SFUD_CMD_WRITE_STATUS_REGISTER;
        cmd_data[1] = status;
        result = spi->wr(spi, cmd_data, 2, NULL, 0);
    }

    if (result != SFUD_SUCCESS) {
        SFUD_INFO("Error: Write_status register failed.");
    }

    return result;
}

